<template>
  <!-- 知识可视化 -->
  <div class="graphVis">
    <drawerPanel v-if="isDrawerPanel">
      <template v-slot:detail>
        <entity-view ref="entityViewX" :ontologyIdNew="ontologyIdNew" v-show="isShowNode" :entityId="entityId"
          :projectId="ontologyAllId" :Neo4j="Neo4jNodeOrEdge" @changeByNode="changeByNode"
          @changeGraphConfig="changeGraphConfig" @cancelNewEntity="cancelNewEntity" @addNewEntity="addNewEntity"
          @changePropertyColor="changePropertyColor" @changePropertyStyle="changePropertyStyle"
          @changeNodeTextSize="changeNodeTextSize" @changeEdgeTextSize="changeEdgeTextSize"></entity-view>
        <relation-view v-show="!isShowNode" :relationId="relationId" :kgEntityRelationSpoId="kgEntityRelationSpoId"
          :projectId="ontologyAllId" :Neo4j="Neo4jNodeOrEdge" @changeByEdge="changeByEdge"
          @addNewRelation="addNewRelation" @cancelNew="cancelNew" @changeGraphConfig="changeGraphConfig"
          @changePropertyColor="changePropertyColor" @changePropertyStyle="changePropertyStyle"
          @changeNodeTextSize="changeNodeTextSize" @changeEdgeTextSize="changeEdgeTextSize"
          ref="editEdgeForm"></relation-view>
      </template>
    </drawerPanel>
    <tabs class="layoutComp" :class="[flag ? '' : 'hideRight']"></tabs>
    <div class="sliderComp" :class="[flag ? '' : 'hideRight']">
      <el-slider v-model="zoomVal" @input="outputZoom" :show-tooltip="false" :step="0.1" :min="0.2" :max="9" vertical
        height="200px"></el-slider>
    </div>
    <!-- <vertical class="verticalComp" :class="[flag ? '' : 'hideRight']"></vertical> -->
    <div class="explainNode" style="top: 16px">
      <my-input ref="myInputData" class="myInputWrapper" @changeByNode="changeByNode" @append_graph="appendGraph">
      </my-input>
    </div>
    <div class="addNodeComp" :class="[flag ? '' : 'hideRight']" @click="toggleDrawer('add')">
      <div>
        <icon-park type="add-one" theme="outline" size="16" fill="#000000" :strokeWidth="2" />
      </div>
      新增节点
    </div>
    <div class="expendNodeComp" :class="[flag ? '' : 'hideRight']" @click="setProperty">
      <div>
        <i class="el-icon-orange"></i>
      </div>
      {{ this.propertyExpend ? "收起属性节点" : "展开属性节点" }}
    </div>
    <div id="graphContainer" ref="graphContainer" class="content"></div>
    <div class="drawer" v-if="isNeedMask"></div>
  </div>
</template>
<script>
import { EventBus } from "@/views/server/knowledge-management/eventBus";
import G6 from "@antv/g6";
import drawerPanel from "../../../components/drawerPanel/knowledgeDrawer.vue";
import entityView from "../knowledge-management/knowledgeBI/component/entityView.vue";
import relationView from "../knowledge-management/knowledgeBI/component/relationView.vue";
import myInput from "@/components/my-input/index.vue";
import tabs from "../position/index.vue";
import { mapState, mapMutations } from "vuex";
import { IconPark } from "@icon-park/vue/es/all";
import { deepClone } from "@/plugins/utils";
import { initBehavors } from "@/behavior/index.js";
export default {
  name: "OntologyModelCreate",
  components: {
    drawerPanel,
    myInput,
    tabs,
    IconPark,
    entityView,
    relationView,
  },
  data() {
    return {
      propertyColor: "#F4D35E",
      propertyStyle: "15",
      propertyListX: [],
      ontologyIdNew: "",
      propertyExpend: false,
      container: null,
      initEntityNodeColor: [],
      imgUrl: "",
      step: null,
      entityId: "",
      relationId: "",
      kgEntityRelationSpoId: "",
      keywords: "",
      restaurants: [],
      ontologyAllId: "",
      addNodeId: null,
      zoomVal: 1,
      width: null,
      height: null,
      graph: null,
      isFrameSelection: true,
      verticalList: [
        {
          title: "只能撤销画布上节点的新增和修改操作",
          icon: "back",
          content: "撤销",
          code: "undo",
          icon: require("@/assets/svg/cancel.svg"),
        },
        {
          title: "下载为图片",
          icon: "download",
          content: "下载",
          code: "download",
          icon: require("@/assets/svg/download.svg"),
        },
        {
          title: "按住shift同时鼠标框选",
          icon: "selected",
          content: "框选",
          code: "frameSelection",
          icon: require("@/assets/svg/frameSelection.svg"),
        },
        {
          title: "清空当前画布内容",
          icon: "erase",
          content: "清空",
          code: "empty",
          icon: require("@/assets/svg/empty.svg"),
        },
      ],
      Nodes: [],
      isShowNode: true,
      isShowRelation: false,
      Neo4jNodeOrEdge: {}, // Neo4j节点或边
      fileUrl: "",
      fileName: "",
      isDrawerPanel: true,
      showSelect: false,
      isNeedMask: false,
      historyNodeId: "",
      historyEdgeId: "",
      graphLeft: "",
      graphTop: "",
      defaultNodeRadius: 16,
      undoList: [], // 可撤销的操作
    };
  },
  created() {
    //初始化 注册 行为 节点 连线
    initBehavors();
    this.animateFun(); // 搜索出来的节点动画
    this.$nextTick(() => {
      EventBus.$on("selectKnowledge", (val) => {
        let obj = val;
        this.ontologyAllId = obj.projectId;
        this.isNeedMask = false;
        // this.ontologyAllId = '157b3ae6-e2e5-4da2-9dc2-b1ea91b911a1'
        this.getGraphDataFun();
      });
      // EventBus.$on('changeNodeColorOrSize', val => {
      //     this.changeNodeColorOrSize(val)
      // });
    });
    this.$eventBus.$on("singleNodeEdit", (obj = null) => {
      if (obj) {
        this.graph.getNodes().forEach((item) => {
          if (obj.nodes.id === item.getModel().ontology_id) {
            const itemModel = deepClone(item.getModel());
            itemModel.color = itemModel.style.fill;
            let model = {};
            if (obj.type === "color") {
              model.color = obj.nodes.color;
            } else {
              model.size = obj.nodes.radius * 2;
            }
            this.change_storeNodes({ ...itemModel, ...model });
          }
        });
        return;
      }
      this.bindEventBusForSingleNodeChange();
    });
    this.$eventBus.$on("singleEdgeEdit", (obj = null) => {
      if (obj) {
        // console.log("obj.edges", obj.edges);
        this.graph.getEdges().forEach((item) => {
          if (
            obj.edges.relationId === item.getModel().relationId ||
            (obj.edges.isPrivate && item.getModel().is_private)
          ) {
            const itemModel = deepClone(item.getModel());
            itemModel.color = itemModel.style.stroke;
            itemModel.isArrow = itemModel.style.endArrow.path !== "";
            let model = {};
            if (obj.type === "color") {
              model.color = obj.edges.color;
            } else if (obj.type === "radius") {
              model.edgeWidth = obj.edges.edgeWidth;
            } else {
              model.isArrow = obj.edges.isArrow;
            }
            this.change_storeEdges({ ...itemModel, ...model });
          }
        });
        return;
      }
      this.bindEventBusForSingleEdgeChange();
    });
    this.change_isVisual(true);
    this.change_storeNodes([]);
    this.change_storeEdges([]);
  },
  mounted() {
    this.container = this.$refs.graphContainer;
    const rect = this.container.getBoundingClientRect();
    this.graphLeft = rect.left;
    this.graphTop = rect.top;
  },
  beforeRouteLeave(to, from, next) {
    this.change_drawer_type_of_node("detail");
    this.change_drawer_type_of_edge("detail");
    this.create_new_edge_of_g6({});
    this.change_current_node();
    this.change_current_edge();
    next();
  },
  beforeDestroy() {
    this.$eventBus.$off("refreshLayout");
    this.$eventBus.$off("toCenter");
    EventBus.$off("selectKnowledge");
    this.$eventBus.$off("get_curAllId");
    EventBus.$off("canvasData");
    this.$eventBus.$off("append_graph");
    this.$eventBus.$off("canvasData");
    this.$eventBus.$off("change_mode");
    this.$eventBus.$off("destroyGraph");
    this.$eventBus.$off("clear_graph");
    this.$eventBus.$off("singleNodeEdit");
    this.$eventBus.$off("singleEdgeEdit");
  },
  computed: {
    ...mapState({
      flag: (state) => state.ontologyModel.drawerFlag,
      graphDatas: (state) => state.ontologyModel.graphDatas,
      drawerTypeOfNode: (state) => state.ontologyModel.drawerTypeOfNode,
      // drawerTypeOfEdge: state => state.knowledgeMap.drawerTypeOfEdge,
      newEdgeOfG6: (state) => state.knowledgeMap.newEdgeOfG6,
      node_config_data: (state) => state.ontologyModel.node_config_data, // 节点数据
      edge_config_data: (state) => state.ontologyModel.edge_config_data, // 边数据
      sidebar: (state) => state.config.sidebar,
      currentNode: (state) => deepClone(state.ontologyModel.currentNode), // 当前选中结点
      currentEdge: (state) => deepClone(state.ontologyModel.currentEdge), // 当前选中边
      storeNodes: (state) => deepClone(state.ontologyModel.storeNodes),
      storeEdges: (state) => deepClone(state.ontologyModel.storeEdges),
    }),
  },
  methods: {
    ...mapMutations({
      change_drawerFlag: "ontologyModel/change_drawerFlag",
      save_nodesId: "knowledgeMap/save_nodesId",
      change_hasGraph: "knowledgeMap/change_hasGraph",
      save_graphData: "ontologyModel/save_graphData",
      change_drawer_type_of_node: "ontologyModel/change_drawer_type_of_node",
      change_drawer_type_of_edge: "knowledgeMap/change_drawer_type_of_edge",
      create_new_edge_of_g6: "knowledgeMap/create_new_edge_of_g6",
      change_current_node: "ontologyModel/change_current_node",
      change_current_edge: "ontologyModel/change_current_edge",
      create_node_config_data: "ontologyModel/create_node_config_data",
      create_edge_config_data: "ontologyModel/create_edge_config_data",
      change_isVisual: "ontologyModel/change_isVisual",
      change_storeNodes: "ontologyModel/change_storeNodes",
      change_storeEdges: "ontologyModel/change_storeEdges",
    }),
    changePropertyColor(val) {
      this.propertyListX.forEach((ens) => {
        if (ens.includes("prop")) {
          this.graph.updateItem(ens, { style: { fill: val } });
        }
      });
      this.propertyColor = val;
    },
    changePropertyStyle(val) {
      this.propertyListX.forEach((ens) => {
        if (ens.includes("prop")) {
          this.graph.updateItem(ens, { size: val * 2 });
        }
      });
      this.propertyStyle = val;
    },
    // 设置节点文字大小
    changeNodeTextSize(val) {
      const nodes = this.graph.getNodes();
      nodes.forEach((item) => {
        this.graph.updateItem(item, {
          labelCfg: {
            style: {
              fontSize: val,
            },
          },
        });
      });
    },
    // 设置边文字大小
    changeEdgeTextSize(val) {
      const edges = this.graph.getEdges();
      edges.forEach((item) => {
        this.graph.updateItem(item, {
          labelCfg: {
            style: {
              fontSize: val,
            },
          },
        });
      });
    },
    setProperty({ isInitSet, initData }) {
      if (this.propertyExpend) {
        this.propertyListX.forEach((es) => {
          this.graph.removeItem(es);
        });
        this.propertyListX = [];
        this.propertyExpend = !this.propertyExpend;
        // if (isInitSet) {
        //   this.changeNodeTextSize(data.textSize)
        //   this.changeEdgeTextSize(data.sideSize)
        //   this.refreshGraphLayout(data.graphLayoutWay)
        //   this.changeGraphConfig({
        //     nodeShape: "2",
        //     nodeLabel: data.nodeLabel
        //   })
        // }
      } else {
        let entityIds = this.graph.getNodes().map((ns) => {
          return ns.getModel().id;
        });
        this.$axios
          .post(this.$api.knowledgeMap.propertyShow, {
            ids: entityIds,
          })
          .then((res) => {
            let data = res.data.data;
            data.forEach((ds) => {
              if (ds.propertyList.length > 0) {
                let ontologyNode = this.graph.findById(ds.entityId).getModel();
                const { x: oldX, y: oldY } = ontologyNode;
                let laynodes = [];
                let layedges = [];
                ds.propertyList.forEach((item, index) => {
                  //半径
                  var radius = 80;
                  //角度

                  //角度计算

                  //角度值
                  var itemAngle = index * 15;
                  //坐标
                  var xx = oldX + radius * Math.sin((itemAngle * 3.14) / 180);
                  var yx = oldY + radius * Math.cos((itemAngle * 3.14) / 180);
                  let newNode;
                  if (item.propertyType == "image") {
                    newNode = {
                      id: ds.entityId + "prop" + index,
                      type: "image",
                      img: item.propertyValue,
                      x: xx,
                      y: yx,
                      size: this.propertyStyle * 2,
                    };
                  }
                  if (item.propertyType == "file") {
                    newNode = {
                      id: ds.entityId + "prop" + index,
                      label: item.fileName,
                      x: xx,
                      y: yx,
                      style: {
                        fill: this.propertyColor,
                      },
                      size: this.propertyStyle * 2,
                    };
                  }
                  if (
                    item.propertyType != "file" &&
                    item.propertyType != "image"
                  ) {
                    newNode = {
                      id: ds.entityId + "prop" + index,
                      label: item.propertyValue,
                      x: xx,
                      y: yx,
                      style: {
                        fill: this.propertyColor,
                      },
                      size: this.propertyStyle * 2,
                    };
                  }
                  // newNode = {
                  //   id: ds.entityId + "prop" + index,
                  //   label: item.propertyValue,
                  //   x: xx,
                  //   y: yx,
                  // };
                  const newEdge = {
                    id: ds.entityId + "edge" + index,
                    source: ds.entityId,
                    target: ds.entityId + "prop" + index,
                    label: item.propertyName,
                  };
                  this.propertyListX.push(ds.entityId + "prop" + index);
                  this.propertyListX.push(ds.entityId + "edge" + index);
                  this.graph.addItem("node", newNode, false);
                  this.graph.addItem("edge", newEdge, false);

                  laynodes.push(
                    this.graph.findById(ds.entityId + "prop" + index).getModel()
                  );
                  layedges.push(
                    this.graph.findById(ds.entityId + "edge" + index).getModel()
                  );
                });
              }
            });
            this.propertyExpend = !this.propertyExpend;
            if (isInitSet) {
              this.changeNodeTextSize(initData.textSize)
              this.changeEdgeTextSize(initData.sideSize)
              this.refreshGraphLayout(initData.graphLayoutWay)
              this.changeGraphConfig({
                nodeShape: "2",
                nodeLabel: initData.nodeLabel
              })
            }
          })
          .catch((err) => {
            // this.$message.error(err);
          });
      }
    },
    isShowSelect() {
      this.showSelect = !this.showSelect;
    },

    clear_graph() {
      this.graph.clear();
      this.save_graphData({});
    },

    changeGraphConfig({ nodeShape, nodeLabel }) {
      if (!this.graph) return;
      const nodes = this.graph.getNodes();
      // 对节点形状的处理
      switch (nodeShape) {
        case "1":
          nodes.forEach((item) => {
            if (item._cfg.model.img) {
              this.graph.updateItem(item, {
                type: "image",
                clipCfg: {
                  show: true,
                },
              });
            }
          });
          // this.graph.render();
          break;
        case "2":
          nodes.forEach((item) => {
            if (item._cfg.model.img) {
              this.graph.updateItem(item, {
                type: "circle",
                clipCfg: {
                  show: false,
                },
              });
            }
          });
          break;
      }
      // 对节点标签的处理
      switch (nodeLabel) {
        case "1":
          nodes.forEach((item) => {
            this.graph.updateItem(item, {
              labelCfg: {
                position: "bottom", //"center"为内嵌，"bottom"为置底
              },
            });
          });
          break;
        case "2":
          nodes.forEach((item) => {
            this.graph.updateItem(item, {
              labelCfg: {
                position: "center", //"center"为内嵌，"bottom"为置底
              },
            });
          });
          break;
      }
      // this.graph.render();
    },
    sxAnalyse() {
      const params = {
        stepLength: Number(this.step),
        entityTypes: [],
        relationTypes: [],
        direction: 2,
        nodeIds: this.Neo4jNodeOrEdge._cfg.id,
      };
      this.$axios
        .post(this.$api.knowledgeMap.filterGraph, params)
        .then((res) => {
          const { data, code, message } = res.data;
          if (code === 200) {
            // this.$message.success(message);
            let data1 = {
              Nodes: data.Nodes,
              Edges: data.Edges,
            };
            // 解决G6 id不是string类型的报错
            data1.Nodes.forEach((item) => {
              item.id = item.id + "";
              item.entity_id = item.nodeId;
              item.label = item.name;
            });
            data1.Edges.forEach((item) => {
              item.source = item.startNodeId;
              item.target = item.endNodeId;
              item.color = item.color;
              // item.color = item.color || '#A9B6C3'
            });
            this.step = "";
            // this.$eventBus.$emit('canvasData', data1);
            this.canvasData(data1);
          } else {
            // this.$message.error(message);
          }
        });
    },
    getGraphDataFun() {
      let elementResizeDetectorMaker = require("element-resize-detector");
      let marker = elementResizeDetectorMaker();
      this.getGraphData(this.ontologyAllId).then((res) => {
        console.log(
          "%c [ res ]-535",
          "font-size:13px; background:pink; color:#bf2c9f;",
          res
        );
        const container = document.getElementById("graphContainer");
        // 获取图谱容器的宽高
        this.getGraphContainerCon();
        if (this.width && this.height) {
          this.$nextTick(() => {
            this.destroyGraph();
            this.initGraph();
            // 初始化图谱交互事件
            this.initGraphEvent();
          });
        }

        if (typeof window !== "undefined" && this.graph) {
          window.onresize = () => {
            if (!this.graph || this.graph.get("destroyed")) return;
            if (!container || !container.scrollWidth || !container.scrollHeight)
              return;
            this.graph.changeSize(
              container.scrollWidth,
              container.scrollHeight
            );
          };
        }
        marker.listenTo(container, () => {
          this.graph.changeSize(container.scrollWidth, container.scrollHeight);
        });
        this.$eventBus.$on("refreshLayout", this.refreshGraphLayout);
        this.$eventBus.$on("toCenter", this.nodeToCenter);
        this.$eventBus.$on("get_curAllId", this.get_curAllNodeId);
        this.$eventBus.$on("append_graph", this.appendGraph);
        this.$eventBus.$on("canvasData", this.canvasData);
        this.$eventBus.$on("change_mode", this.change_graphMode);
        this.$eventBus.$on("download", this.downloadGraph);
        this.$eventBus.$on("destroyGraph", this.destroyGraph);
        this.$eventBus.$on("clear_graph", this.clear_graph);
      });
    },
    get_curAllNodeId() {
      let all = [];
      this.graph.getNodes().forEach((item) => {
        all.push(item._cfg.id);
      });
      this.save_nodesId(all);
    },
    destroyGraph() {
      if (this.graph) {
        this.graph.destroy();
        this.change_hasGraph(false);
      }
    },
    changeByNode(data) {
      let { flag, nodes, addEdge, delEdgeID } = data;
      // 新增节点 （新增边和节点/只新增节点）add操作，编辑节点（只改变节点，改变节点和删除边，改变节点和新增边，改变节点和删除和新增边）search 节点并更新，
      if (this.drawerTypeOfNode === "add") {
        let singleNode = this.addNode(data);
        this.graph.setItemState(singleNode, "click", true);
      } else {
        // this.update_node(node);
        this.updateNode(data);
        // 查找节点并更新 find setItem
      }
      // if (this.flag) {
      //   if (addEdge) {
      //     this.addEdge(addEdge);
      //   }
      //   if (delEdgeID) {
      //     this.removeEdge({
      //       id: delEdgeID,
      //     });
      //   }
      // }
      if (flag) {
        if (Array.isArray(addEdge)) {
          addEdge.forEach((item) => {
            this.addEdge(item);
          });
        } else {
          if (addEdge && addEdge.id) {
            this.addEdge(addEdge);
            // 新增的边push add
          }
          if (delEdgeID) {
            this.removeEdge({
              id: delEdgeID,
            });
            // 删除的边 splice remove
          }
        }
      }
      this.historyEdgeId = "";
      this.historyEdgeId = "";
      // this.addNodeId = node.id;
      // this.drawerType = 'detail';
      // this.graph.getItem()
      // 存储operationId
      if (data.operationType && data.operationId) {
        this.undoList.push({
          type: data.operationType,
          operationId: data.operationId,
        });
      }
      // console.log(this.undoList);
    },
    // 监听边新增/更新
    changeByEdge(edgeData, type) {
      if (type === "add") {
        // this.$nextTick(() => {
        let newModel = edgeData.reaData;
        this.graph.addItem("edge", newModel);
        this.graph.refresh();
        this.clearAllStates();
        this.graph.setMode("default");
        this.isNeedMask = false;

        let sourceNode = this.graph.save().nodes.filter((item) => {
          return item.entity_id === this.newEdgeOfG6.sourceId;
        })[0];

        this.graph.getEdges().forEach((edge) => {
          let isHasArrow = edge.getModel().type === "loop" ? false : true;
          let distance = this.defaultNodeRadius + 2;
          this.graph.updateItem(edge, {
            style: {
              endArrow: isHasArrow
                ? {
                  path: G6.Arrow.triangle(5, 10, distance),
                  d: distance,
                }
                : false,
            },
          });
        });
        // 【todo: 为了解决新增线和已存在的重合问题】
        G6.Util.processParallelEdges(this.graph.save().edges);
        const item = this.graph.findById(sourceNode.id);
        const model = Object.assign({}, sourceNode);
        model.x = parseFloat(item.x) + 1;
        model.y = parseFloat(item.y) + 1;
        this.graph.refreshItem(item);
        this.graph.updateItem(item, model);
        this.graph.refresh();
        // })
      } else {
        this.updateEdge(edgeData.id, edgeData);
      }
      this.historyEdgeId = "";
      this.historyNodeId = "";
    },

    // 获取图谱容器的宽高
    getGraphContainerCon() {
      const graphCon = document.getElementById("graphContainer");
      this.width = graphCon.offsetWidth;
      this.height = graphCon.offsetHeight;
    },
    // 缩放图谱
    outputZoom(val) {
      if (this.graph) {
        this.graph.zoomTo(val);
      }
      // console.log("zoomv", this.zoomVal);
    },
    // 获取图谱中所有节点的 id 组成的数组
    getAllNodeId() {
      let arrId = [];
      this.graph.getNodes().forEach((item) => {
        arrId.push(item.getModel().id);
      });
      // 将数据存到 store
      this.save_nodesId(arrId);
      return arrId;
    },
    // 将目标节点移到图中心
    nodeToCenter(val) {
      const node = this.graph.findById(val);
      let model = {
        type: "circle-animate",
      };
      // 添加动画
      this.graph.updateItem(node, model);
      // 整体移动图谱使得当前节点位于中心
      this.graph.focusItem(node, true, {
        easing: "easeCubic",
        duration: 500,
      });
      let timer = setTimeout(() => {
        model = {
          type: "circle",
        };
        this.graph.updateItem(node, model);
      }, 3500);
      timer = null;
    },
    // 新增节点
    toggleDrawer() {
      this.change_drawer_type_of_node("add");
      this.entityId = "";
      this.isShowNode = true;
      this.isNeedMask = true;
      // 先发开侧边栏, 添加节点信息, 之后保存, 使用返回的信息构建 model, 然后添加节点
      if (this.flag) {
        this.change_drawerFlag();
      }
      this.change_current_node({});
    },
    appendGraph(params) {
      const { Nodes, Edges } = params;
      let data1 = {
        Nodes: Nodes,
        Edges: Edges,
      };
      this.save_graphData({
        Nodes,
        Edges,
      });
      const { nodesIds, edgesIds } = this.getALLGrapgData();
      data1.Nodes.forEach((item) => {
        if (nodesIds.indexOf(`${item.id}`) == -1) {
          item.id = item.id + "";
          item.x = Math.random() * 500;
          item.y = Math.random() * 300;
          item.style = {
            fill: item.color,
          };
          item.entity_id = item.entity_id;
          item.label = item.name;
          let addNode = this.graph.addItem("node", item);
          this.clearAllStates();
          addNode && this.graph.setItemState(addNode, "click", true);
        }
      });
      data1.Edges.forEach((item) => {
        if (edgesIds.indexOf(`${item.id}`) == -1) {
          item.source = item.startNodeId;
          item.target = item.endNodeId;
          this.graph.addItem("edge", item);
        }
      });
      G6.Util.processParallelEdges(data1.Edges);
      // 获取画布上的数据
    },
    canvasData(val) {
      this.save_graphData(val);
      this.destroyGraph();
      this.initGraph();
      // 初始化图谱交互事件
      this.initGraphEvent();

      // if (!this.graph.destroyed) {
      //   this.save_graphData(val);
      //   this.destroyGraph();
      // }
      // this.$nextTick(() => {
      //   if (this.graph.destroyed) {
      //     this.initGraph();
      //     // 初始化图谱交互事件
      //     this.initGraphEvent();
      //   }
      // })
    },
    addNode(node) {
      const point = this.graph.getPointByClient(
        this.graphLeft + 1165,
        this.graphTop + 100
      );
      let { id, color, entity_id, label } = node;
      const model = {
        type: "circle",
        x: point.x,
        y: point.y,
        id,
        color,
        entity_id,
        label,
        style: {
          fill: color, // 填充色
          stroke: "#BFC0C0", // 描边颜色
          lineWidth: 1, // 描边宽度
          cursor: "pointer",
        },
      };
      let node1 = this.graph.addItem("node", model, false);
      return node1;
    },
    updateNode(nodeData) {
      let { id, entity_id } = nodeData;
      const node = this.graph.findById(id);
      this.graph.updateItem(node, nodeData);
    },
    async deleteNodeFun(nodeData) {
      let { entity_id } = nodeData;
      let params = {
        status: 1,
        entityId: entity_id,
      };
      let res = await this.$axios.post(
        this.$api.knowledgeMap.deleteNode,
        params
      );
      if (res.data) {
        if (res.data.code === 200) {
          this.removeNode(nodeData);
        }
        if (res.data.code === 10003) {
          // this.$message.error(res.data.message);
        }
        if (res.data.code === 10004) {
          // this.$message.error(res.data.message);
        }
      }
    },
    removeNode(nodeData) {
      let { id } = nodeData;
      const node = this.graph.findById(id);
      this.graph.removeItem(node);
    },
    // 新增边
    addEdge(edgeData) {
      this.graph.addItem("edge", edgeData);
      const edges = this.graph.save().edges;
      G6.Util.processParallelEdges(edges);
    },

    // 更新边
    updateEdge(id, edgeData) {
      const edge = this.graph.findById(id);
      let oldModel = edge.getModel();
      let { label } = edgeData;
      let model = {
        ...oldModel,
        label,
      };
      this.graph.updateItem(edge, model);
      this.graph.setItemState(edge, "click", true);
    },
    async deleteEdgeFun(edgeData) {
      let { kgEntityRelationSpoId } = edgeData;
      let params = {
        kgEntityRelationSpoId: kgEntityRelationSpoId,
      };
      let res = await this.$axios.get(this.$api.knowledgeMap.deleteRelation, {
        params,
      });
      if (res.data && +res.data.code === 200) {
        this.removeEdge(edgeData);
        this.$message.success(res.data.msg);
      } else {
        // this.$message.error(res.data.msg);
      }
    },
    removeEdge(edgeData) {
      let { id } = edgeData;
      const edge = this.graph.findById(id);
      this.graph.removeItem(edge);
    },
    // 重新布局
    refreshGraphLayout(val) {
      // console.log("refreshGraphLayout", val);
      if (this.graph) {
        // console.log("val", val);
        if (!val) {
          // console.log("gForce    ");
          this.graph.updateLayout({
            type: "force",
            // damping: 0.5,
            linkDistance: 300,
            preventOverlap: true, // 防止节点覆盖
            // gpuEnabled: true,
          });
        } else {
          this.graph.updateLayout({
            // type: val,
            // linkDistance: 300,
            // preventOverlap: true, // 防止节点覆盖
            // gpuEnabled: true,
            type: 'dendrogram', // 布局类型
            direction: 'LR', // 自左至右布局，可选的有 H / V / LR / RL / TB / BT
            nodeSep: 50, // 节点之间间距
            rankSep: 100, // 每个层级之间的间距
          });
        }
      } else {
        this.$notify({
          title: "提示",
          message: "请先生成图谱！",
          type: "warning",
          duration: 1500,
        });
      }
    },
    // 切换全屏
    toggleFullScreen() {
      const graphContainer = document.getElementById("graphContainer");
      const canvas = graphContainer.querySelector("canvas");
      if (!canvas.fullscreenElement) {
        canvas.requestFullscreen();
      } else {
        if (canvas.exitFullscreen) {
          canvas.exitFullscreen();
        }
      }
    },

    // 清除所有样式
    clearAllStates() {
      this.graph.getNodes().forEach((item) => {
        this.graph.clearItemStates(item);
      });
      this.graph.getEdges().forEach((item) => {
        this.graph.clearItemStates(item);
      });
    },

    claerItemClicked() {
      const clickedEdges = this.graph.findAllByState("edge", "click");
      clickedEdges.forEach((ce) => {
        this.graph.setItemState(ce, "click", false);
      });
      // 先将所有的 click 状态的节点置为非 click 状态
      const clickedNodes = this.graph.findAllByState("node", "click");
      clickedNodes.forEach((cn) => {
        this.graph.setItemState(cn, "click", false);
      });
    },

    // 通过点击建模获取的 id 获取图谱数据
    getGraphData(ontologyAllId) {
      const params = {
        projectId: ontologyAllId,
      };
      return this.$axios
        .get(this.$api.knowledgeMap.getAllData, {
          params,
        })
        .then((res) => {
          let data = res.data.data;
          this.initEntityNodeColor = deepClone(data.Nodes);

          // debugger;
          data.Nodes.forEach((item) => {
            if (item.entity_status == "1") {
              item.img = item.name;
              item.type = "image";
              item.labelCfg = {
                style: {
                  opacity: 0, // 图片不显示label
                },
              };
              // 裁剪图片配置
              item.clipCfg = {
                show: true,
                type: "circle",
                r: 15,
              };
            }
            // if (item.img) {
            //   this.getImg(item.img).then((res) => {
            //     item.img = res;
            //     // item.type = "image";
            //     // // 裁剪图片配置
            //     // item.clipCfg = {
            //     //   show: false,
            //     //   type: "circle",
            //     //   r: 30,
            //     // };
            //   });
            // }
          });
          let propertyColor =
            data.propertyColor == "" ? "#F4D35E" : data.propertyColor;
          let propertyStyle =
            data.propertyStyle == "" ? "15" : data.propertyStyle;
          this.propertyColor = propertyColor;
          this.propertyStyle = propertyStyle;
          this.$refs.entityViewX.setPropertyColor(propertyColor);
          this.$refs.entityViewX.setPropertyStyle(propertyStyle);
          this.$refs.editEdgeForm.setPropertyColor(propertyColor);
          this.$refs.editEdgeForm.setPropertyStyle(propertyStyle);
          this.save_graphData(data);
          return data;
        })
        .catch((err) => {
          // this.$message.error(err);
        });
    },

    getALLGrapgData() {
      const { edges, nodes } = this.graph.save();
      const nodesIds = [];
      const edgesIds = [];
      nodes.forEach((item) => {
        nodesIds.push(item.id);
      });
      edges.forEach((item) => {
        edgesIds.push(item.id);
      });
      return {
        nodes,
        edges,
        nodesIds,
        edgesIds,
      };
    },

    // 展开节点接口
    async expandGraph(entity_id, all) {
      let oldEntityIdList = [];
      this.graphDatas.Nodes.forEach((item) => {
        oldEntityIdList.push(item.entity_id);
      });
      let res = await this.$axios.post(this.$api.knowledgeMap.expandGraph, {
        entityId: entity_id,
        oldEntityIdList: oldEntityIdList,
      });
      const { data, code, message } = res.data;
      if (code === 200) {
        const { Nodes, Edges } = data;
        const { nodesIds, edgesIds } = this.getALLGrapgData();
        const { x: oldX, y: oldY } = all;
        // 解决G6 id不是string类型的报错
        Nodes.forEach((item) => {
          if (nodesIds.indexOf(`${item.id}`) == -1) {
            item.id = item.id + "";
            item.x = oldX;
            item.y = oldY;
            item.color = item.color;
            item.style = {
              fill: item.color,
              stroke: "#BFC0C0",
            };
            item.entity_id = item.entity_id;
            item.label = item.name;
            let addNode = this.graph.addItem("node", item, false);
            addNode && this.graph.setItemState(addNode, "default", true);
          }
        });
        Edges.forEach((item) => {
          if (edgesIds.indexOf(`${item.id}`) == -1) {
            item.source = item.startNodeId;
            item.target = item.endNodeId;
            item.id = item.id + "";
            // item.color = item.color || '#8D99AE'
            item.color = item.color;
            this.graph.addItem("edge", item);
          }
        });
        this.graph.paint();
        G6.Util.processParallelEdges(Edges);
        const subLayout = new G6.Layout.circular({
          center: [oldX, oldY],
          linkDistance: 300,
          preventOverlap: true,
          // animate: true,
          tick: () => {
            this.graph.refreshPositions();
          },
        });
        let nodes = Nodes.map((node) => {
          node.id = "" + node.id;
          return node;
        });
        let edges = Edges.map((edge) => {
          edge.id = "" + edge.id;
          return edge;
        });
        subLayout.init({
          nodes,
          edges,
        });
        subLayout.execute();
        this.graph.positionsAnimate();
        // this.$eventBus.$emit('canvasData', data1);
        // this.canvasData(data1)
        this.handleArrow();

        // this.graph.updateLayout({
        //   linkDistance: 300,
        //   damping: 0.2,
        //   preventOverlap: true,
        //   minMovement: 0.9,
        // });
      } else {
        // this.$message.error(message);
      }
    },

    handleArrow() {
      G6.Util.processParallelEdges(this.graph.save().edges);
      this.graph.getEdges().forEach((edge) => {
        let isHasArrow = edge.getModel().type === "loop" ? false : true;
        let distance = this.defaultNodeRadius + 2;
        this.graph.updateItem(edge, {
          style: {
            endArrow: isHasArrow
              ? {
                path: G6.Arrow.triangle(5, 10, distance),
                d: distance,
              }
              : false,
          },
        });
      });
    },

    getImg(url) {
      let fileName = url.split("/");
      const params = {
        fileUrl: url,
        fileName: fileName[fileName.length - 1],
      };

      return this.$axios({
        methods: "get",
        url: this.$api.knowledgeMap.downLoadFileUrl,
        params: params,
        responseType: "blob",
      }).then((res) => {
        let blob = new Blob([res.data]);
        let imgUrl = window.URL.createObjectURL(blob);
        this.imgUrl = imgUrl;
        return imgUrl;
      });
    },

    animateFun() {
      G6.registerNode(
        "circle-animate",
        {
          afterDraw(cfg, group) {
            // 获取该节点上的第一个图形
            const shape = group.get("children")[0];
            // 该图形的动画
            shape.animate(
              (ratio) => {
                // 每一帧的操作，入参 ratio：这一帧的比例值（Number）。返回值：这一帧需要变化的参数集（Object）。
                // 先变大、再变小
                const diff = ratio <= 0.5 ? ratio * 10 : (1 - ratio) * 10;
                let radius = cfg.size;
                if (isNaN(radius)) radius = radius[0];
                // 返回这一帧需要变化的参数集，这里只包含了半径
                return {
                  r: radius / 2 + diff,
                };
              },
              {
                // 动画重复
                repeat: false,
                duration: 3000,
                easing: "easeCubic",
              }
            ); // 一次动画持续的时长为 3000，动画效果为 'easeCubic'
          },
        },
        "circle"
      );
    },
    addNewRelation(val) {
      // this.relationId = val;
      this.kgEntityRelationSpoId = val;
    },
    cancelNew() {
      this.graph.zoom(1); //【todo： 解决新增线不可消除】
      this.graph.setMode("default");
      this.isNeedMask = false;

      if (this.historyEdgeId) {
        this.isShowNode = false;
        this.relationId = this.historyEdgeId;
        // this.kgEntityRelationSpoId = this.historyEdgeId
      }
      if (this.historyNodeId) {
        this.isShowNode = true;
        this.entityId = this.historyNodeId;
      }
      this.historyNodeId = "";
      this, (this.historyEdgeId = "");
      // // 【todo: 为了解决新增线和已存在的重合问题】
      // let sourceNode= this.graph.save().nodes.filter(item=> {
      //     return item.entity_id===this.newEdgeOfG6.sourceId
      // })[0]
      // let targetNode= this.graph.save().nodes.filter(item=> {
      //     return item.entity_id===this.newEdgeOfG6.targetId
      // })[0]
      // G6.Util.processParallelEdges(this.graph.save().edges);
      // const item = this.graph.findById(sourceNode.id);
      // const model= Object.assign({}, sourceNode);
      // model.x= parseFloat(item.x)+1;
      // model.y= parseFloat(item.y)+1;
      // this.graph.refreshItem(item);
      // this.graph.updateItem(item, model);
      // this.graph.refresh();
    },
    cancelNewEntity() {
      this.isNeedMask = false;
      if (this.historyEdgeId) {
        this.isShowNode = false;
        this.relationId = this.historyEdgeId;
        // this.kgEntityRelationSpoId = this.historyEdgeId
      }
      if (this.historyNodeId) {
        this.isShowNode = true;
        this.entityId = this.historyNodeId;
      } else {
        this.isShowNode = true;
        this.entityId = this.graphDatas.Nodes.length
          ? this.graphDatas.Nodes[0].entity_id
          : "";
      }
      this.historyNodeId = "";
      this, (this.historyEdgeId = "");
    },
    addNewEntity(val) {
      this.entityId = val;
      this.isNeedMask = false;
    },
    // 框选
    // 切换图的行为模式
    change_graphMode(val) {
      this.graph.setMode(val);
    },
    // 下载图谱
    downloadGraph(type) {
      if (this.graph) {
        this.graph.downloadFullImage("知识图谱", type, {
          backgroundColor: "#ddd",
          padding: [30, 15, 15, 15],
        });
      } else {
        this.$notify({
          title: "提示",
          message: "请先生成图谱！",
          type: "warning",
          duration: 1500,
        });
      }
    },
    // 下载svg图片
    downloadSvgGraph() {
      this.graph.toFullDataURL(
        (res) => {
          // 获取导出图片的高宽信息
          const imgTmp = new Image();
          imgTmp.src = res;
          imgTmp.onload = () => {
            const svgData = `<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="${imgTmp.width}" height="${imgTmp.height}" style="background-color: #ddd;"><defs></defs><g><image width="${imgTmp.width}" height="${imgTmp.height}" preserveAspectRatio="none" xlink:href="${res}"></image></g></svg>`;
            const blobData = new Blob([svgData], {
              type: "image/svg+xml;charset=utf-8",
            });
            const svgUrl = URL.createObjectURL(blobData);
            const link = document.createElement("a");
            link.href = svgUrl;
            link.download = "知识图谱.svg";
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);
            URL.revokeObjectURL(svgUrl);
          };
        },
        "image/png",
        {
          backgroundColor: "#ddd",
          padding: [30, 15, 15, 15],
        }
      );
    },
    initGraph() {
      this.graph = null;
      // 小地图
      const minimap = new G6.Minimap({
        size: [200, 100],
      });
      // 右键菜单
      const contextMenu = new G6.Menu({
        shouldBegin(evt) {
          if (evt.target && evt.target.isCanvas && evt.target.isCanvas())
            return true;
          if (evt.item) return true;
          return false;
        },
        getContent(evt) {
          const { item } = evt;
          const itemType = item.getType();
          const model = item.getModel();
          if (itemType && model) {
            if (itemType === "node") {
              return `<ul>
                                <li  id='connect'>连线</li>
                                <li id='extendnode'>展开</li>
                                <li id='hidenode'>收起</li>
                                <li id='hideme'>隐藏</li>
                                <li id='delete'>删除</li>
                                </ul>`;
            } else if (itemType === "edge") {
              return `<ul>
                                <li  id='delete'>删除</li>
                                </ul>`;
            }
          }
        },
        handleMenuClick: (target, item) => {
          const liIdStrs = target.id.split("-");
          switch (liIdStrs[0]) {
            case "connect":
              this.clearAllStates();
              this.graph.setMode("create-edge");
              this.graph.emit("node:click", {
                item,
              });

              // const singleNode = e.item.getModel();
              break;
            case "extendnode":
              const g2 = this.graph.getNeighbors(item._cfg.id, "target");
              for (let i = 0; i < g2.length; i++) {
                this.graph.showItem(g2[i]._cfg.id);
              }
              // 与双击节点效果相同
              // const singleNode = item.getModel();
              // this.expandGraph(singleNode.entity_id);
              break;
            case "hidenode":
              const g1 = this.graph.getNeighbors(item._cfg.id, "target");
              for (let i = 0; i < g1.length; i++) {
                this.graph.hideItem(g1[i]._cfg.id);
              }
              break;
            case "hideme":
              // debugger
              // this.graph.hideItem(item._cfg.id);
              this.graph.removeItem(item._cfg.id);
              const ddd = this.graph.save();
              const { nodes: Nodes, edges: Edges } = ddd;
              this.save_graphData({
                Nodes,
                Edges,
              });
              break;
            case "delete":
              if (item.getModel().type == "circle") {
                // 删除节点
                this.deleteNodeFun(item.getModel());
              } else {
                // 删除边
                this.deleteEdgeFun(item.getModel());
              }
            default:
              break;
          }
        },
        itemTypes: ["node", "edge"],
      });
      // 工具栏
      const toolbar = new G6.ToolBar({
        className: "toolbar",
        getContent: () => {
          let list = this.verticalList.map((item) => {
            if (item.code != "download") {
              return `
              <li code="${item.code}" class="toolbar-item">
                <div class="toolbar-main">
                  <img src="${item.icon}" style="width: 16px; height: 16px; margin-left: 4px;" />
                  <div>${item.content}</div>
                </div>
                <span class="toolbar-tips" style="left: -150px;top: -4px;">${item.title}</span>
              </li>`;
            } else {
              return `
              <li class="toolbar-item">
                <div class="toolbar-main">
                  <img src="${item.icon}" style="width: 16px; height: 16px; margin-left: 4px;" />
                  <div>${item.content}</div>
                </div>
                <div class="toolbar-opera">
                  <span id="pngDownload" code="pngCode">png图片</span>
                  <span id="jpgDownload" code="jpgCode">jpg图片</span>
                  <span id="svgDownload" code="svgCode">svg图片</span>
                </div>
              </li>`;
            }
          });
          list = list.join("");
          return `<ul id='toolBar'>${list}</ul>`;
        },
        handleClick: (code, graph) => {
          switch (code) {
            case "undo":
              // 撤销节点的新增和修改
              // toolbar.undo();
              this.undo();
              break;
            case "download":
              if (graph && graph.save().nodes.length != 0) {
                graph.downloadFullImage("图谱", "image/png", {
                  backgroundColor: "#ddd",
                  padding: [30, 15, 15, 15],
                });
              } else {
                this.$notify({
                  title: "提示",
                  message: "请先生成图谱！",
                  type: "warning",
                  duration: 1500,
                });
              }
              break;
            case "fullScreen":
              this.toggleFullScreen();
              break;
            case "frameSelection":
              if (graph.getCurrentMode() != "box-select") {
                this.clearAllStates();
                graph.setMode("box-select");
                this.isFrameSelection = false;
              } else {
                this.clearAllStates();
                graph.setMode("default");
              }
              break;
            case "empty":
              this.$confirm(
                "是否确认清空当前画布上的全部图谱？清空后不可恢复",
                "提示",
                {
                  confirmButtonText: "确定",
                  cancelButtonText: "取消",
                  type: "warning",
                }
              )
                .then(() => {
                  // 接口返回删除成功后, 再销毁画布
                  // if (!this.$store.state.hasGraph) {
                  if (true) {
                    // this.$message({
                    //   type: "success",
                    //   message: "删除成功!",
                    // });
                    // this.clear_graph();
                    // 清空数据
                    this.clearGraph();
                  }
                })
                .catch(() => {
                  this.$message({
                    type: "info",
                    message: "已取消删除",
                  });
                });
            default:
              break;
          }
        },
      });

      this.graph = new G6.Graph({
        container: "graphContainer",
        width: this.width,
        height: this.height,
        linkCenter: true,
        renderer: "canvas",
        plugins: [minimap, contextMenu, toolbar],
        // plugins: [minimap, contextMenu],
        animate: true,
        enabledStack: true,
        layout: {
          type: "gForce",
          linkDistance: 300,
          preventOverlap: true, // 防止节点覆盖
          //   workerEnabled: true,
          // gpuEnabled: true,
          //   nodeStrength: 3500,
          // coulombDisScale: 1,
        },
        // 交互模式：包括节点和边的信息浮框, 缩放/拖拽画布、节点等
        modes: {
          default: [
            {
              type: "drag-canvas",
              enableOptimize: true,
            },
            "drag-node",
            {
              type: "zoomCanvas",
              minZoom: 0.2,
              maxZoom: 10,
            },
            {
              type: "brush-select",
              trigger: "shift",
            },
            //  {
            //     type: 'lasso-select',
            //     delegateStyle: {
            //         fill: '#f00',
            //         fillOpacity: 0.05,
            //         stroke: '#f00',
            //         lineWidth: 1,
            //     },
            //     // onSelect: (nodes, edges) => {
            //     // },
            //     trigger: 'shift',
            // },
          ],
          "box-select": ["brush-select", "drag-node"],
          "create-edge": [
            "drag-canvas",
            "drag-node",
            {
              type: "add-edge",
              edgeConfig: {
                label: "未命名",
                type: "line",
                style: {
                  stroke: "#E63946",
                },
                labelCfg: {
                  autoRotate: true,
                  style: {
                    fill: "#247BA0",
                    //导致G6画线错误的地方：原因是 fontSize:"16px" 导致text文本渲染错误，catchBBox 重新渲染区域盒子获取数据有误
                    fontSize: 16,
                    fontWeight: 700,
                  },
                },
              },
            },
          ],
        },
        //默认状态下节点的配置
        defaultNode: {
          size: 30,
          style: {
            fill: "#F4D35E", // 填充色
            stroke: "#BFC0C0", // 描边颜色
            lineWidth: 1, // 描边宽度
            cursor: "pointer",
          },
          labelCfg: {
            position: "bottom",
          },
          clipCfg: {
            show: false,
            type: "circle",
            r: 30,
            // // ellipse
            // rx: 10,
            // ry: 15,
            // // rect
            // width: 15,
            // height: 15,
            // // 坐标
            // x: 0,
            // y: 0,
          },
        },
        //默认状态下边的配置
        defaultEdge: {
          type: "line",
          style: {
            lineWidth: "2",
            stroke: "#A9B6C3",
            endArrow: {
              path: G6.Arrow.triangle(5, 10, this.defaultNodeRadius + 2),
              d: this.defaultNodeRadius + 2,
            },
          },
          labelCfg: {
            autoRotate: true,
          },
        },
        //各个状态下节点的样式
        nodeStateStyles: {
          hover: {
            fill: "lightsteelblue",
          },
          click: {
            stroke: "#086788",
            lineWidth: 2,
          },
          default: {
            stroke: "#BFC0C0",
            linkWidth: 1,
          },
        },
        //各个状态下边的样式
        edgeStateStyles: {
          click: {
            stroke: "#FFB997",
          },
        },
      });
      setTimeout(() => {
        const pngDownload = document.getElementById("pngDownload");
        const jpgDownload = document.getElementById("jpgDownload");
        const svgDownload = document.getElementById("svgDownload");
        pngDownload.addEventListener("click", () => {
          this.downloadGraph("image/png");
        });
        jpgDownload.addEventListener("click", () => {
          this.downloadGraph("image/jpeg");
        });
        svgDownload.addEventListener("click", () => {
          this.downloadSvgGraph();
        });
      }, 1000);
      const { Nodes, Edges } = this.graphDatas;

      this.getEntityType();
      this.getRelationStyle();
      Nodes.forEach((node) => {
        node.style = {
          fill: node.color,
        };
      });

      Edges.forEach((edge) => {
        if (edge["source"] == edge["target"]) {
          edge.type = "loop";
        }
        edge.style = {
          stroke: edge.color,
        };
      });
      // for (let i = 0; i < Edges.length; i++) {
      //   const element = Edges[i];
      //   if (element["source"] == element["target"]) {
      //     element.type = "loop";
      //   }
      // }
      G6.Util.processParallelEdges(Edges);
      this.graph.getEdges().forEach((edge, i) => {
        this.graph.updateItem(edge, {
          curveOffset: edges[i].curveOffset,
          curvePosition: edges[i].curvePosition,
        });
      });
      this.graph.data({
        nodes: Nodes,
        edges: Edges,
      }); // 读取远程数据到图上
      this.graph.render();
      this.graph.getEdges().forEach((edge) => {
        let isHasArrow = edge.getModel().type === "loop" ? false : true;
        let distance = this.defaultNodeRadius + 2;
        this.graph.updateItem(edge, {
          style: {
            endArrow: isHasArrow
              ? {
                path: G6.Arrow.triangle(5, 10, distance),
                d: distance,
              }
              : false,
          },
        });
      });
      // 处理多条关系不分离的问题
      // G6.Util.processParallelEdges(Edges);
      // this.animateFun(); // 搜索出来的节点动画

      // 保存所有节点的 id(搜索定位的功能使用该项)
      this.getAllNodeId();

      const zoom = this.graph.getZoom();
      this.graph.get("canvas").set("localRefresh", false); // 局部刷新解决节点移动时画布上存在移动轨迹问题
      //将graph对象发布给组件
      this.$eventBus.$emit("getGraph", this.graph);
      this.getConfigDetail()
    },

    getConfigDetail() {
      this.$axios
        .get(this.$api.setting.showConfigApi.getConfigDetail)
        .then((res) => {
          const { data, code } = res.data;
          if (code == 200) {
            // console.log(data, 'data');
            if (data.entityPropertyNode == '默认展开') {
              this.propertyExpend = false
            } else {
              this.propertyExpend = true
            }
            if (data.nodeLabel == '文字置底') {
              data.nodeLabel = "1"
            } else {
              data.nodeLabel = "2"
            }
            console.log(this.propertyExpend, 'this.propertyExpend');
            this.setProperty({
              isInitSet: true,
              initData: data
            })
            this.changeNodeTextSize(data.textSize)
            this.changeEdgeTextSize(data.sideSize)
            this.refreshGraphLayout(data.graphLayoutWay)
            this.changeGraphConfig({
              nodeShape: "2",
              nodeLabel: data.nodeLabel
            })
          }
        });
    },

    unique(arr, val) {
      const res = new Map();
      return arr.filter((item) => !res.has(item[val]) && res.set(item[val], 1));
    },

    getRelationStyle() {
      let params = {
        projectId: this.$store.state.knowledgeMap.projectMsg.projectId,
      };
      this.$axios
        .get(this.$api.knowledgeMap.getRelationStyle, {
          params,
        })
        .then((res) => {
          const { data, code, message } = res.data;
          if (code === 200) {
            // data.forEach(item => {
            //     if (item.isPrivate == 0) {
            //         item.label = item.relationName;
            //     } else {
            //         item.label = "私有属性";
            //     }
            // });
            data.forEach((item) => {
              item.id = item.relationId;
            });
            this.create_edge_config_data(data);
          } else {
            // this.$message.error(`${message}2341241`);
          }
        });
    },
    getEntityType() {
      let params = {
        projectId: this.$store.state.knowledgeMap.projectMsg.projectId,
      };
      this.$axios
        .get(this.$api.knowledgeMap.getEntityType, {
          params,
        })
        .then((res) => {
          const { data, code, message } = res.data;
          if (code === 200) {
            // debugger;
            this.ontologyIdNew = data.length ? data[0].ontologyAllId : "";
            // let res = data.list.map(item => {
            let res = data.map((item) => {
              item.label = item.ontologyName;
              item.color = item.color;
              item.id = item.ontologyId;
              return item;
            });
            res.forEach((item) => {
              this.initEntityNodeColor.forEach((node) => {
                if (item.ontologyId === node.ontology_id) {
                  item.color = node.color;
                }
              });
            });
            this.create_node_config_data(deepClone(res));
          } else {
            // this.$message.error(message);
          }
        });
    },
    initGraphEvent() {
      this.graph.on("cancelCreatEdge", (edgeItem) => {
        this.clearAllStates();
        this.graph.setMode("default");
      });
      this.graph.on("wheelzoom", (zoomVal) => {
        if (zoomVal >= 9.15) {
        } else {
          this.zoomVal = zoomVal;
        }
      });
      // '画布上'连线完成之后, 切换一下模式
      this.graph.on("aftercreateedge", (edgeItem) => {
        this.isShowNode = false;
        this.isNeedMask = true;
        // this.relationId = '';
        this.kgEntityRelationSpoId = "";
        if (this.historyEdgeId) {
          this.historyNodeId = "";
        }
        // this.change_drawer_type_of_edge('add');
        // 先发开侧边栏, 添加节点信息, 之后保存, 使用返回的信息构建 model, 然后添加节点
        if (this.flag) {
          this.change_drawerFlag();
        }
        const singleEdge = edgeItem.edge.getModel();

        let { id, source, target } = singleEdge;
        let sourceNode = this.graph.findById(source).getModel();

        let targetNode = this.graph.findById(target).getModel();

        let sourceId = sourceNode.entity_id;
        let targetId = targetNode.entity_id;
        let sourceOntoId = sourceNode.ontology_id;
        let targetOntoId = targetNode.ontology_id;
        let sourceName = sourceNode.label;
        let targetName = targetNode.label;
        let sourceStatus = sourceNode.entity_status;
        let targetStatus = targetNode.entity_status;
        this.create_new_edge_of_g6({
          edgeId: id,
          sourceId,
          targetId,
          sourceName,
          targetName,
          sourceOntoId,
          targetOntoId,
          sourceStatus,
          targetStatus,
        });
        this.$nextTick(() => {
          let delEdgeId = this.newEdgeOfG6.edgeId;
          this.removeEdge({
            id: delEdgeId,
          });
        });
        this.clearAllStates();
      });

      this.graph.on("node:click", async (e) => {
        if (this.flag) {
          this.change_drawerFlag();
        }
        // 取消所有点/边被单击的状态
        this.claerItemClicked();
        // this.isShowRelation=false;
        // this.isShowNode = true
        // 获取当前点击的节点
        this.Neo4jNodeOrEdge = Object.assign({}, e.item);

        const nodeItem = e.item;
        this.graph.setItemState(nodeItem, "click", true);
        const singleNode = e.item.getModel();

        this.entityId = singleNode.entity_id;
        this.historyNodeId = singleNode.entity_id;
        this.change_current_node(singleNode);
        this.change_drawer_type_of_node("detail");
        // if (this.flag) {
        //     this.change_drawerFlag();
        // }
        this.isShowNode = true;
      });
      this.graph.on("node:dblclick", async (e) => {
        // 取消所有点/边被单击的状态
        this.claerItemClicked();
        const nodeItem = e.item;
        this.graph.setItemState(nodeItem, "click", true);
        const singleNode = e.item.getModel();
        let entity_id = singleNode.entity_id;
        this.historyNodeId = singleNode.entity_id;
        this.expandGraph(entity_id, singleNode);
      });
      this.graph.on("edge:click", async (e) => {
        this.isShowNode = false;
        if (this.flag) {
          this.change_drawerFlag();
        }
        this.Neo4jNodeOrEdge = Object.assign({}, e.item);
        // 取消所有点/边被单击的状态
        this.claerItemClicked();
        // 获取当前点击的线
        const edgeItem = e.item;
        this.graph.setItemState(edgeItem, "click", true);

        const singleEdge = e.item.getModel();
        if (this.kgEntityRelationSpoId === singleEdge.kgEntityRelationSpoId) {
          this.kgEntityRelationSpoId = "";
          this.$nextTick(() => {
            this.kgEntityRelationSpoId = singleEdge.kgEntityRelationSpoId;
          });
        } else {
          this.kgEntityRelationSpoId = singleEdge.kgEntityRelationSpoId;
        }
        this.relationId = singleEdge.relation_id || singleEdge.relationId;
        // this.historyEdgeId = singleEdge.relation_id || singleEdge.relationId;
        this.historyEdgeId = singleEdge.kgEntityRelationSpoId;
        const { source, target } = singleEdge;
        const sourceOntoId = this.graph.findById(source).getModel().ontology_id;
        const targetOntoId = this.graph.findById(target).getModel().ontology_id;

        this.change_current_edge({
          sourceOntoId,
          targetOntoId,
          ...singleEdge,
        });
        this.change_drawer_type_of_edge("detail");

        this.isShowRelation = true;
      });

      // 当 click-select 选中的元素集合发生变化时将会触发下面时机事件，e 中包含相关信息
      this.graph.on("nodeselectchange", (e) => {
        // 当前操作后，所有被选中的 items 集合
        // console.log(e.selectedItems);
        // 当前操作时选中(true)还是取消选中(false)
        // console.log(e.select);
      });
    },
    // 同步面板与画布中节点配置的函数
    changeNodeColorFun() {
      let configData = deepClone(this.node_config_data);
      configData.shift();
      this.graph.getNodes().forEach((item) => {
        configData.forEach((data) => {
          console.log(
            "%c [ data ]-1941",
            "font-size:13px; background:pink; color:#bf2c9f;",
            data
          );
          if (data.id === item.getModel().ontology_id) {
            // let model = {
            //   size: data.radius * 2,
            //   style: {
            //     fill: data.color,
            //   },
            // };
            // this.graph.updateItem(item, model); // 0827注掉
            // 在更改节点半径的同时修改连线箭头的偏移量
            this.graph.getEdges().forEach((x) => {
              if (x.getModel().target == item.getModel().id) {
                let customArrow = {
                  path: G6.Arrow.triangle(5, 10, item.getModel().size / 2 + 2),
                  d: item.getModel().size / 2 + 2,
                };
                let isHasArrow = x.getModel().type === "loop" ? false : true;
                let model = {
                  style: {
                    endArrow: isHasArrow ? customArrow : false,
                  },
                };
                this.graph.updateItem(x, model);
              }
            });
          }
        });
      });
      this.bindEventBusForSingleNodeChange();
    },

    changeNodeSize(val) {
      let nodeArr = this.graphDatas.Nodes.filter((item) => {
        return item.ontology_id === val.ontologyId;
      });
      this.graph.getNodes().forEach((item) => {
        nodeArr.forEach((data) => {
          if (data.id === item.getModel().id) {
            let model = {
              size: val.radius * 2,
              style: {
                fill: val.color,
              },
            };
            this.graph.updateItem(item, model);
          }
        });
      });
    },
    // 同步面板与画布中连线配置的函数
    changeEdgeColorFun() {
      // 处理多条关系不分离的问题
      G6.Util.processParallelEdges(this.graph.save().edges);
      let customArrow = {
        path: G6.Arrow.triangle(5, 10, this.defaultNodeRadius + 2),
        d: this.defaultNodeRadius + 2,
      };
      let configData = deepClone(this.edge_config_data);
      configData.shift();
      this.graph.getEdges().forEach((item) => {
        configData.forEach((data) => {
          let isHasArrow = item.getModel().type === "loop" ? false : true;
          if (data.isPrivate == 1 && item.getModel().is_private == 1) {
            let model = {
              style: {
                stroke: data.color,
                lineWidth: data.edgeWidth,
                endArrow: isHasArrow && data.isArrow ? customArrow : false,
              },
            };
            item.setState("click", false);
            this.graph.updateItem(item, model);
          } else {
            if (data.relationId === item.getModel().relationId) {
              // console.log("data", data);
              let model = {
                style: {
                  stroke: data.color,
                  lineWidth: data.edgeWidth,
                  endArrow: isHasArrow && data.isArrow ? customArrow : false,
                },
              };
              // console.log("model", model);
              item.setState("click", false);
              this.graph.updateItem(item, model);
            }
          }
        });
      });
      this.bindEventBusForSingleEdgeChange();
    },
    async undo() {
      if (this.undoList.length == 0) {
        this.$message.warning("没有操作可撤销了！");
        return;
      }
      let params = {
        operationId: this.undoList[this.undoList.length - 1].operationId,
      };
      let res = await this.$axios.get(this.$api.knowledgeMap.undo, {
        params,
      });
      let type = this.undoList[this.undoList.length - 1].type;
      if (res.data.code === 200) {
        this.undoList.pop();
        if (type == 1) {
          // 新增
          // 刷新画布
          this.removeEdge({
            id: res.data.data,
          });
        } else {
          // 修改
          this.changeByNode(res.data.data);
          // this.changeByEdge(res.data.data, "edit");
        }
      }
    },
    async clearGraph() {
      let res = await this.$axios.get(this.$api.knowledgeMap.clearGraph, {
        params: {
          projectId: this.$store.state.knowledgeMap.projectMsg.projectId,
        },
      });
      if (res.data.code === 200) {
        this.$message({
          type: "success",
          message: "删除成功!",
        });
        this.clear_graph();
      } else {
        this.$message.error(res.data.message);
      }
    },
    bindEventBusForSingleNodeChange() {
      this.graph?.getNodes().forEach((item) => {
        this.storeNodes.forEach((node) => {
          if (node.id === item.getModel().id) {
            let model = {
              size: node.size,
              style: {
                fill: node.color,
              },
            };
            this.$nextTick(() => {
              this.graph.updateItem(item, model);
            });
          }
        });
      });
    },
    bindEventBusForSingleEdgeChange() {
      // console.log("@触发edge", this.storeEdges);
      // 处理多条关系不分离的问题
      G6.Util.processParallelEdges(this.graph.save().edges);
      let customArrow = {
        path: G6.Arrow.triangle(5, 10, this.defaultNodeRadius + 2),
        d: this.defaultNodeRadius + 2,
      };
      this.graph?.getEdges().forEach((item) => {
        this.storeEdges.forEach((edge) => {
          let isHasArrow = item.getModel().type === "loop" ? false : true;
          if (edge.id === item.getModel().id) {
            let model = {
              style: {
                stroke: edge.color,
                lineWidth: edge.edgeWidth,
                endArrow: isHasArrow && edge.isArrow ? customArrow : false,
              },
            };
            // console.log("@model", model);

            this.$nextTick(() => {
              item.setState("click", false);
              this.graph.updateItem(item, model);
            });
          }
        });
      });
    },
  },

  watch: {
    // zoomVal(newVal, oldVal) {
    //   this.graph.zoomTo(newVal);
    // },
    node_config_data: {
      handler: function (newVal, oldVal) {
        console.log(
          "%c [ watch node_config_data ]-2123",
          "font-size:13px; background:pink; color:#bf2c9f;"
        );
        this.changeNodeColorFun();
      },
      deep: true,
    },
    edge_config_data: {
      handler: function (newVal, oldVal) {
        this.changeEdgeColorFun();
      },
      deep: true,
    },
    "$store.state.knowledgeMap.projectMsg.projectId": {
      handler: function () {
        // 解决子组件不刷新问题
        this.isDrawerPanel = false;
        this.$nextTick(() => {
          this.isDrawerPanel = true;
          this.entityId = "";
          this.relationId = "";
          // this.kgEntityRelationSpoId = ''
        });
      },
      immediate: true,
    },
  },
};
</script>
<style lang="scss" scoped>
.graphVis {
  width: 100%;
  height: 100%;
  top: -52px;
  position: relative;

  #graphContainer {
    width: 100%;
    height: calc(100% - 16px);
    margin-top: 28px;

    /deep/ canvas {
      left: 0;
      bottom: 0;
      width: 100% !important;
      height: 100% !important;
      z-index: -1 !important;
      background: #f3f4f8;
      cursor: pointer;
    }

    /deep/ canvas:-webkit-full-screen {
      width: 100%;
      height: 100%;
    }

    /deep/ .g6-minimap {
      position: absolute !important;
      right: 60px !important;
      bottom: 0px !important;
      overflow: visible !important;
    }

    /deep/.g6-minimap-container {
      border: 1px solid #e2e2e2;
      overflow: hidden;
    }

    // /deep/ .g6-minimap-viewport {
    //   width: 150px !important;
    //   // height: 98px;
    //   left: auto;
    //   top: auto;
    //   margin-left: 2px;
    //   margin-top: 2px;
    // }

    /deep/ .g6-component-contextmenu {
      position: absolute;
      z-index: 2;
      list-style-type: none;
      background-color: #f8f8f8;
      border-radius: 6px;
      font-size: 14px;
      color: #333333;
      width: fit-content;
      transition: opacity 0.2s;
      text-align: center;
      box-shadow: 0 5px 18px 0 rgba(200, 200, 200, 0.9);
      border: 0px;
    }

    /deep/ .g6-component-contextmenu ul {
      padding-left: 0px;
      margin: 0;
    }

    /deep/ .g6-component-contextmenu li {
      padding: 0px 20px 0px 20px;
      cursor: pointer;
      list-style-type: none;
      list-style: none;
      margin-left: 0;
      line-height: 38px;
    }

    /deep/ .g6-component-contextmenu li:hover {
      font-size: 14px;
      font-family: MicrosoftYaHei;
      color: #3a58b9;
    }

    /deep/ .el-button {
      width: 67px;
    }

    /deep/.toolbar.hideRight {
      right: 500px;
    }

    /deep/ .toolbar {
      position: absolute;
      right: 50px;
      top: 240px;
      color: #545454;
      cursor: pointer;
      width: 48px;
      padding: 0;
      margin: 0;

      li {
        position: relative;
        width: 48px;
        height: 48px;
        background: #ffffff;
        margin-bottom: 4px;
        font-size: 12px;
        border-radius: 4px;
        cursor: pointer;
        transition: 1s;

        &:hover {
          background-color: wheat;
        }

        .toolbar-main {
          position: relative;
          width: 100%;
          height: 100%;
          display: flex;
          flex-direction: column;
          justify-content: center;
          align-items: center;

          &:hover {
            &+.toolbar-tips {
              z-index: 0;
              opacity: 1;
            }

            &+.toolbar-opera {
              z-index: 0;
              opacity: 1;
            }
          }
        }

        .toolbar-opera {
          position: absolute;
          left: -150px;
          top: -4px;
          opacity: 0;
          transition: 1s;
          z-index: -1;

          &:hover {
            z-index: 0;
            opacity: 1;
          }

          >span {
            display: block;
            box-shadow: 1px 1px 4px;
            background: white;
            padding: 5px;
            color: black;
            border-radius: 6px;
            width: 130px;
            text-align: center;

            &:not(:last-child) {
              margin-bottom: 10px;
            }
          }
        }

        .toolbar-tips {
          opacity: 0;
          box-shadow: 1px 1px 4px;
          position: absolute;
          background: white;
          padding: 5px;
          color: black;
          border-radius: 6px;
          width: 130px;
          text-align: center;
          transition: 1s;
          z-index: -1;

          &:hover {
            z-index: 0;
            opacity: 1;
          }
        }

        // .icon {
        //   position: relative;

        //   span {
        //     position: absolute;
        //     left: 16px;
        //     top: 4px;
        //   }
        // }

        // .content {
        //   position: relative;
        //   top: 20px;
        //   text-align: center;
        // }
      }
    }
  }

  .layoutComp {
    position: absolute;
    right: 50px;
    top: 18px;
    transition: right 0.7s ease 0s;
    border-radius: 4px;
    z-index: 9;
  }

  .hideRight.layoutComp {
    right: 474px;
  }

  .verticalComp {
    position: absolute;
    right: 45px;
    bottom: 430px;
    transition: right 0.7s ease 0s;
    z-index: 9;
  }

  .hideRight.verticalComp {
    right: 426px;
  }

  .sliderComp {
    position: absolute;
    right: 50px;
    top: 500px;
    transition: right 0.7s ease 0s;
    z-index: 99;

    /deep/ .el-slider {
      height: 150px;
    }

    .el-slider {
      height: 100px !important;
    }
  }

  .hideRight.sliderComp {
    right: 426px;
  }

  /deep/ .el-slider__button-wrapper {
    width: 30px;
    height: 30px;
    left: -12px;
  }

  /deep/ .el-slider__button {
    width: 10px;
    height: 10px;
  }

  /deep/ .el-input__inner {
    height: 40px;
    line-height: 40px;
    font-size: 14px;
    box-shadow: 0px 4px 4px 4px rgba(172, 176, 191, 0.14);
  }

  .addNodeComp {
    width: 100px;
    height: 40px;
    display: flex;
    justify-content: space-evenly;
    align-items: center;
    position: absolute;
    right: 525px;
    top: 18px;
    box-shadow: 0px 4px 4px 4px rgba(172, 176, 191, 0.14);
    border-radius: 4px;
    background-color: #fff;
    transition: right 0.7s ease 0s;
    font-size: 14px;
    color: #333333;
    z-index: 9;

    &:hover {
      border-color: #3a58b9;
      cursor: pointer;
    }

    span {
      display: flex;
      align-items: center;
    }
  }

  .expendNodeComp {
    width: 120px;
    height: 40px;
    display: flex;
    justify-content: space-evenly;
    align-items: center;
    position: absolute;
    right: 400px;
    top: 18px;
    box-shadow: 0px 4px 4px 4px rgba(172, 176, 191, 0.14);
    border-radius: 4px;
    background-color: #fff;
    transition: right 0.7s ease 0s;
    font-size: 14px;
    color: #333333;
    z-index: 9;

    &:hover {
      border-color: #3a58b9;
      cursor: pointer;
    }

    span {
      display: flex;
      align-items: center;
    }
  }

  .explainNode {
    position: absolute;
    top: 72px;
    width: 276px;
    height: 40px;
    z-index: 9;

    // margin-top: 16px;
    /deep/ .el-input-group {
      width: 276px;
    }

    /deep/ .el-input-group__append {
      box-sizing: border-box;
    }
  }

  .explainNode-icon {
    position: absolute;
    top: 72px;
    width: 40px;
    height: 40px;
    box-sizing: border-box;
    background: #ffffff;
    box-shadow: 0px 4px 4px 4px rgba(172, 176, 191, 0.14);
    border-radius: 2px;
    border: 1px solid #dddddd;
  }

  .explainNode-icon-show {
    position: absolute;
    top: 0;
    width: 32px;
    height: 32px;
    box-sizing: border-box;
    background: #ffffff;
    box-shadow: 0px 4px 4px 4px rgba(172, 176, 191, 0.14);
    border-radius: 2px;
    border: 1px solid #dddddd;
  }

  /deep/ .el-input-group__append,
  .el-input-group__prepend {
    background-color: #4b71eb;
    color: #ffffff;
    font-size: 14px;
    height: 32px;
  }

  .hideRight.addNodeComp {
    right: 949px;
  }

  .hideRight.expendNodeComp {
    right: 824px;
  }

  .myOption {
    display: flex;
    justify-content: space-between;
    align-items: center;
    text-align: left;

    span:first-of-type {
      // min-width: 40px;
      height: 24px;
      font-size: 12px;
      border-radius: 12px;
      background: #f2f2f2;
      max-width: 74px;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }

    span:last-of-type {
      // min-width: 87px;
      // height: 19px;
      font-size: 12px;
      border-radius: 12px;
      background: #f2f2f2;
      max-width: 74px;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }

    p {
      flex-grow: 1;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
      padding-left: 10px;
    }
  }

  .step-setup {
    /deep/ .el-input__inner {
      padding-left: 40px;
    }
  }

  .drawer-close {
    right: 0;
  }

  .drawer {
    position: absolute;
    z-index: 1001;
    top: 0;
    bottom: 0;
    background: rgba(0, 0, 0, 0.3);
    right: 400px;
    left: -24px;
    // transition: background 0.7s ease 0s;
    display: block;
  }
}
</style>
